package com.jidecai.pro.view;



import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;

public class ScrollLayout extends ViewGroup {

//	private static final String TAG = "ScrollLayout";

	private Scroller mScroller;

	private int currentIndex;

	private VelocityTracker mVelocityTracker;

	private static final int SHOWING_VIEW = 1;

	private int mWidth;

	private static final int TOUCH_STATE_REST = 0;

	private static final int TOUCH_STATE_SCROLLING = 1;

	private static final int SNAP_VELOCITY = 600;

	private HashMap<Integer, OnScreenChangeListener> listeners;

	private int mTouchState = TOUCH_STATE_REST;

	private int mTouchSlop;

	private float mLastMotionX;

	private float mLastMotionY;

	public ScrollLayout(Context context, AttributeSet attrs) {

		this(context, attrs, 0);

	}

	@Override
	protected void dispatchDraw(Canvas canvas) {
		super.dispatchDraw(canvas);
	}

	public ScrollLayout(Context context, AttributeSet attrs, int defStyle) {

		super(context, attrs, defStyle);

		mScroller = new Scroller(context);

		mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

		listeners = new HashMap<Integer, ScrollLayout.OnScreenChangeListener>();

	}

	@Override
	protected void attachViewToParent(View child, int index, LayoutParams params) {

		super.attachViewToParent(child, index, params);
	}

	@Override
	public void addView(View child) {

		super.addView(child);
	}

	@Override
	public void requestChildFocus(View child, View focused) {
		super.requestChildFocus(child, focused);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {

		int childLeft = 0;

		final int childCount = getChildCount();

		for (int i = 0; i < childCount; i++) {

			final View childView = getChildAt(i);

			if (childView.getVisibility() != View.GONE) {

				final int childWidth = childView.getMeasuredWidth();

				childView.layout(childLeft, 0,

				childLeft + childWidth, childView.getMeasuredHeight());

				childLeft += childWidth;

			}

		}
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

		final int width = MeasureSpec.getSize(widthMeasureSpec);

		final int widthMode = MeasureSpec.getMode(widthMeasureSpec);

		if (widthMode != MeasureSpec.EXACTLY) {

			throw new IllegalStateException(
					"ScrollLayout only canmCurScreen run at EXACTLY mode!");

		}

		final int heightMode = MeasureSpec.getMode(heightMeasureSpec);

		if (heightMode != MeasureSpec.EXACTLY) {

			throw new IllegalStateException(
					"ScrollLayout only can run at EXACTLY mode!");

		}

		// The children are given the same width and height as the scrollLayout

		final int count = getChildCount();

		for (int i = 0; i < count; i++) {

			getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);

		}

		scrollTo(SHOWING_VIEW * width, 0);

	}

	/**
	 * 
	 * According to the position of current layout
	 * 
	 * scroll to the destination page.
	 */

	public void snapToDestination() {

		setMWidth();

		final int destScreen = (getScrollX() + mWidth / 2) / mWidth;

		snapToScreen(destScreen);

	}

	private void setMWidth() {
		if (mWidth == 0) {
			mWidth = getWidth();
		}
	}

	public void snapToScreen(int whichScreen) {

		// get the valid layout page

		whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));

		setMWidth();

		int scrollX = getScrollX();
		int startWidth = whichScreen * mWidth;

		boolean beChange = true;

		if (scrollX != startWidth) {

			int delta = 0;
			int startX = 0;

			if (whichScreen > SHOWING_VIEW) {

				setPre();
				delta = startWidth - scrollX;
				startX = mWidth - startWidth + scrollX;

			} else if (whichScreen < SHOWING_VIEW) {

				setNext();
				delta = -scrollX;
				startX = scrollX + mWidth;
			} else {
				startX = scrollX;
				delta = startWidth - scrollX;
				beChange = false;

			}

			mScroller.startScroll(startX, 0, delta, 0, Math.abs(delta) * 2);

			invalidate(); // Redraw the layout

		}

		// 閫氱煡鐩戝惉鍣�
		if (beChange && !listeners.isEmpty()) {
			Iterator<Entry<Integer, OnScreenChangeListener>> iterator = listeners
					.entrySet().iterator();
			while (iterator.hasNext()) {
				Map.Entry<Integer, OnScreenChangeListener> entry = (Map.Entry<Integer, ScrollLayout.OnScreenChangeListener>) iterator
						.next();
				OnScreenChangeListener listener = entry.getValue();
				listener.onScreenChange(currentIndex);
			}
		}

		// startCurrentView();

	}

	public int getCurrentScreenIndex() {
		return currentIndex;
	}

	public void scrollToScreen(int whichScreen) {
		snapToScreen(whichScreen);
	}

	public void setCurrentScreenIndex(int whichScreen) {
		whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));

		scrollTo(whichScreen * mWidth, 0);

		if (whichScreen > SHOWING_VIEW) {
			setPre();
		} else if (whichScreen < SHOWING_VIEW) {
			setNext();
		}

		this.currentIndex = whichScreen;

	}

	public View getCurScreen() {

		return this.getChildAt(SHOWING_VIEW);

	}

	@Override
	public void computeScroll() {

		if (mScroller.computeScrollOffset()) {
			scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
			postInvalidate();

		}

	}

	private void setNext() {
		int count = this.getChildCount();
		View view = getChildAt(count - 1);
		removeViewAt(count - 1);
		addView(view, 0);

		this.currentIndex = currentIndex < 1 ? count - 1 : currentIndex - 1;

	}

	private void setPre() {
		int count = this.getChildCount();
		View view = getChildAt(0);
		removeViewAt(0);
		addView(view, count - 1);

		this.currentIndex = currentIndex > count - 2 ? 0 : currentIndex + 1;

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		if (mVelocityTracker == null) {

			mVelocityTracker = VelocityTracker.obtain();

		}

		mVelocityTracker.addMovement(event);

		final int action = event.getAction();

		final float x = event.getX();

		switch (action) {

		case MotionEvent.ACTION_DOWN:

			if (!mScroller.isFinished()) {

				mScroller.abortAnimation();
				// mScroller.forceFinished(false);

			}

			mLastMotionX = x;

			break;

		case MotionEvent.ACTION_MOVE:

			int deltaX = (int) (mLastMotionX - x);

			mLastMotionX = x;

			scrollBy(deltaX, 0);

			break;

		case MotionEvent.ACTION_UP:

			// if (mTouchState == TOUCH_STATE_SCROLLING) {

			final VelocityTracker velocityTracker = mVelocityTracker;

			velocityTracker.computeCurrentVelocity(1000);

			int velocityX = (int) velocityTracker.getXVelocity();

			if (velocityX > SNAP_VELOCITY && SHOWING_VIEW > 0) {

				snapToScreen(SHOWING_VIEW - 1);

			} else if (velocityX < -SNAP_VELOCITY

			&& SHOWING_VIEW < getChildCount() - 1) {

				snapToScreen(SHOWING_VIEW + 1);

			} else {

				snapToDestination();

			}

			if (mVelocityTracker != null) {

				mVelocityTracker.recycle();

				mVelocityTracker = null;

			}

			// }

			mTouchState = TOUCH_STATE_REST;
			break;

		case MotionEvent.ACTION_CANCEL:

			mTouchState = TOUCH_STATE_REST;

			break;

		}

		return true;

	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {

		// Log.d(TAG, "onInterceptTouchEvent-slop:" + mTouchSlop);

		final int action = ev.getAction();

		if ((action == MotionEvent.ACTION_MOVE) &&

		(mTouchState != TOUCH_STATE_REST)) {

			return true;

		}

		final float x = ev.getX();
		final float y = ev.getY();

		switch (action) {

		case MotionEvent.ACTION_MOVE:

			final int xDiff = (int) Math.abs(mLastMotionX - x);
			final int yDiff = (int) Math.abs(mLastMotionY - y);

			/*
			 * if (xDiff > mTouchSlop) {
			 * 
			 * mTouchState = TOUCH_STATE_SCROLLING;
			 * 
			 * }
			 */

			if (xDiff > mTouchSlop && xDiff > yDiff * 3.5) {
				// mIsBeingDragged = true;
				mTouchState = TOUCH_STATE_SCROLLING;
			}

			break;

		case MotionEvent.ACTION_DOWN:

			mLastMotionX = x;

			mLastMotionY = y;

			mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST
					: TOUCH_STATE_SCROLLING;

			break;

		case MotionEvent.ACTION_CANCEL:

		case MotionEvent.ACTION_UP:

			mTouchState = TOUCH_STATE_REST;

			break;

		}

		return mTouchState != TOUCH_STATE_REST;

	}

	@Override
	protected void onAttachedToWindow() {

		super.onAttachedToWindow();
	}

	@Override
	public void dispatchWindowFocusChanged(boolean hasFocus) {
		super.dispatchWindowFocusChanged(hasFocus);
	}

	@Override
	public void dispatchWindowVisibilityChanged(int visibility) {

		super.dispatchWindowVisibilityChanged(visibility);
	}

	@Override
	public void onWindowFocusChanged(boolean hasWindowFocus) {

		super.onWindowFocusChanged(hasWindowFocus);
	}

	@Override
	protected void onWindowVisibilityChanged(int visibility) {

		super.onWindowVisibilityChanged(visibility);
	}

	@Override
	protected void onDetachedFromWindow() {

		super.onDetachedFromWindow();
	}

	public interface OnScreenChangeListener {
		void onScreenChange(int currentIndex);
	}

	public void setOnScreenChangeListener(
			OnScreenChangeListener onScreenChangeListener) {
		addOnScreenChangeListener(-9898, onScreenChangeListener);
	}

	public void addOnScreenChangeListener(int tag,
			OnScreenChangeListener onScreenChangeListener) {
		listeners.put(tag, onScreenChangeListener);
	}

	public void removeScreenChangeListener(int tag) {
		listeners.remove(tag);
	}

	public void removeAllScreenChangeListener() {
		listeners.clear();
	}
}
